////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __WN_MATH_INTERNAL_ELEMENTS_INL__
#define __WN_MATH_INTERNAL_ELEMENTS_INL__

#ifndef __WN_MATH_INTERNAL_ELEMENTS_H__
    #error "Internal/x86/SSE/WNElements.inl should never be included directly."
#endif

namespace WNMath {
    namespace __WNInternal {
        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsAddGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element1.mValues[i] += _element2.mValues[i];
            }

            return(_element1);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsAddGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] += _number;
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSubtractGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element1.mValues[i] -= _element2.mValues[i];
            }

            return(_element1);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSubtractGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] -= _number;
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplyGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element1.mValues[i] *= _element2.mValues[i];
            }

            return(_element1);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplyGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] *= _number;
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsDivideGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element1.mValues[i] /= _element2.mValues[i];
            }

            return(_element1);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsDivideGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] /= _number;
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplyAddGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2, const __WNElements<Type, Dimension>& _element3) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element1.mValues[i] *= _element2.mValues[i];
                _element1.mValues[i] += _element3.mValues[i];
            }

            return(_element1);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplyAddGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number1, const Type& _number2) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] *= _number1;
                _element.mValues[i] += _number2;
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplySubtractGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2, const __WNElements<Type, Dimension>& _element3) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element1.mValues[i] *= _element2.mValues[i];
                _element1.mValues[i] = (_element3.mValues[i] - _element1.mValues[i]);
            }

            return(_element1);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplySubtractGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number1, const Type& _number2) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] *= _number1;
                _element.mValues[i] = (_number2 - _element.mValues[i]);
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsZeroGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] = static_cast<Type>(0);
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsOneGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] = static_cast<Type>(1);
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSetGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] = _number;
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSetGeneric<Type, Dimension>::Execute(__WNElements<Type, Dimension>& _element, const Type* _numbers) {
            for (WN_UINT32 i = 0; i < Dimension; ++i) {
                _element.mValues[i] = _numbers[i];
            }

            return(_element);
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsAdd<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            return(__WNElementsAddGeneric<Type, Dimension>::Execute(_element1, _element2));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsAdd<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            return(__WNElementsAddGeneric<Type, Dimension>::Execute(_element, _number));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSubtract<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            return(__WNElementsSubtractGeneric<Type, Dimension>::Execute(_element1, _element2));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSubtract<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            return(__WNElementsSubtractGeneric<Type, Dimension>::Execute(_element, _number));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiply<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            return(__WNElementsMultiplyGeneric<Type, Dimension>::Execute(_element1, _element2));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiply<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            return(__WNElementsMultiplyGeneric<Type, Dimension>::Execute(_element, _number));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsDivide<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2) {
            return(__WNElementsDivideGeneric<Type, Dimension>::Execute(_element1, _element2));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsDivide<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            return(__WNElementsDivideGeneric<Type, Dimension>::Execute(_element, _number));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplyAdd<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2, const __WNElements<Type, Dimension>& _element3) {
            return(__WNElementsMultiplyAddGeneric<Type, Dimension>::Execute(_element1, _element2, _element3));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplyAdd<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number1, const Type& _number2) {
            return(__WNElementsMultiplyAddGeneric<Type, Dimension>::Execute(_element, _number1, _number2));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplySubtract<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element1, const __WNElements<Type, Dimension>& _element2, const __WNElements<Type, Dimension>& _element3) {
            return(__WNElementsMultiplySubtractGeneric<Type, Dimension>::Execute(_element1, _element2, _element3));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsMultiplySubtract<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number1, const Type& _number2) {
            return(__WNElementsMultiplySubtractGeneric<Type, Dimension>::Execute(_element, _number1, _number2));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsZero<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element) {
            return(__WNElementsZeroGeneric<Type, Dimension>::Execute(_element));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsOne<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element) {
            return(__WNElementsOneGeneric<Type, Dimension>::Execute(_element));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSet<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type& _number) {
            return(__WNElementsSetGeneric<Type, Dimension>::Execute(_element, _number));
        }

        template <typename Type, WN_UINT32 Dimension, typename Enabled>
        WN_FORCE_INLINE __WNElements<Type, Dimension>& __WNElementsSet<Type, Dimension, Enabled>::Execute(__WNElements<Type, Dimension>& _element, const Type* _numbers) {
            return(__WNElementsSetGeneric<Type, Dimension>::Execute(_element, _numbers));
        }
    }
}

#endif // __WN_MATH_INTERNAL_ELEMENTS_INL__